<?php


namespace App\controllers;

use App\models\Products;
use Core\annotations\Bean;
use Core\annotations\Lock;
use Core\annotations\Redis;
use Core\annotations\RequestMapping;
use Core\http\Request;
use Core\lib\RedisHelper;

/**
 * Class ProductController
 * @package App\controllers
 * @Bean()
 */
class ProductController
{

    /**
     * @Redis(script="return redis.call('get', 'name')")
     * @RequestMapping(value="/prod/script")
     */
    public function testscript()
    {
        //测试
        return __METHOD__;
    }

    /**
     * @Redis(prefix="hprods", key="#prod_id", type="hash")
     * @RequestMapping(value="'/prods")
     */
    public function preheat(Request $request)
    {
        $prods = Products::all();
        return $prods;
    }


    /**
     * @Redis(prefix="stock", key="prod_id", member="prod", score="prod_stock", type="sortedset", coroutine=1)
     * @RequestMapping(value="'/prod/stock")
     */
    public function stock(Request $request)
    {

        //协程读取
        //先实例化 channel，通过go函数,获取数据并存入channel，最后返回channel
        $channel = new \Swoole\Coroutine\Channel(1);
        go(function () use ($channel) {
            $prods = Products::all();
            $channel->push($prods);
        });

        return $channel;
    }

    /**
     * 测试购买
     * @Lock(prefix="lockprod", key="#0", retry="1")
     * @RequestMapping(value="/prod/buy/{pid:\d+}")
     */
    public function buy(Request $request, int $pid)
    {
        $key = 'stock';
        $member = 'prod' . $pid;

        $prodStock = RedisHelper::zScore($key, $member);
        if ($prodStock && $prodStock > 0) {
            $newValue = RedisHelper::zIncrBy($key, -1, $member);
            return $newValue;
        }

        return 0;
    }

    /**
     * 锁的基本原理
     */
    public function locks()
    {
        /**
         * 使用 setnx 命令
         *  表示对某个key设置值， 如果key不存在，则设置成功，返回1，
         *  如果key存在，则设置失败， 返回 0
         *  伪代码如下 :
         *  while(!redis::setnx('lock', xx)) {
         *   //休眠若干毫秒
         * }
         *
         *  //做业务处理 ......................
         *
         *  redis::del('lock'); //释放锁，其他请求则可以继续进入
         *
         */

        /**
         * Lua 脚本实现
         */
        $script = <<<LUA
    local key = KEYS[1]
    return redis.call('setnx', key, 1)
LUA;


    }

}